package com.xmall.timer.manager;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import com.xmall.timer.dto.TimerTaskDto;
import com.xmall.timer.dto.TimerTaskHistory;
import com.xmall.timer.dto.TimerTaskRunInfo;
import com.xmall.timer.handler.ITimerTaskHandler;
import com.xmall.utils.CronExpParserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TimerTaskManager {

    /**
     * key：处理器 taskHandler
     * val: 任务编码
     */
    private static Map<ITimerTaskHandler, String> taskKeyMap = new HashMap<>();

    /**
     * key：任务编码
     * val: 处理器 taskHandler
     */
    private static Map<String, ITimerTaskHandler> taskHandlerMap = new HashMap<>();

    /**
     * key：处理器 taskHandler
     * val：任务运行时信息
     */
    public static Map<ITimerTaskHandler, TimerTaskRunInfo> taskRunInfoMap = new HashMap<>();

    /**
     * key：任务编码
     * val：任务cron
     */
    public static Map<String, String> taskCronMap = new HashMap<>();

    /**
     * key：任务编码
     * val：任务对象
     */
    private static Map<String, ScheduledFuture> taskFutureMap = new HashMap<>();

    /**
     * 任务列表
     */
    private static Map<String, List<TimerTaskHistory>> futureMap = new HashMap<>();

    /**
     * 任务调度器
     */
    @Resource
    private TaskScheduler taskScheduler;

    /**
     * 任务处理器列表
     */
    private List<ITimerTaskHandler> taskHandlerList = new ArrayList<>();

    @Autowired(required = false)
    public void setTaskHandlerList(List<ITimerTaskHandler> taskHandlerList) {
        this.taskHandlerList = taskHandlerList;
    }

    /**
     * 获取处理器
     */
    public ITimerTaskHandler getTaskHandler(String key) {
        return taskHandlerMap.get(key);
    }

    /**
     * 开启定时任务调度
     */
    @PostConstruct
    public void startTimerTaskSchedule() {
        log.info("TimerTaskManager task num: {}", taskHandlerList.size());

        taskHandlerList.forEach(taskHandler -> {
            String key = taskHandler.key();
            ScheduledFuture<?> future = taskScheduler.schedule(() -> runTask(taskHandler), new CronTrigger(taskHandler.cron()));

            log.info("TimerTaskManager task start: {}", taskHandler.getClass().getSimpleName());

            taskKeyMap.put(taskHandler, key);
            taskHandlerMap.put(key, taskHandler);

            taskCronMap.put(key, taskHandler.cron());
            taskFutureMap.put(key, future);

            TimerTaskHistory history = new TimerTaskHistory();
            history.setFuture(future);
            history.setCron(taskHandler.cron());
            futureMap.computeIfAbsent(key, k -> new ArrayList<>()).add(history);
        });
    }

    /**
     * 重启任务
     */
    public void restartTask(String taskKey, String currentCron) {
        log.info("TimerTaskManager restartTask, taskKey: {}, cron: {}", taskKey, currentCron);

        ScheduledFuture future = taskFutureMap.get(taskKey);
        if(null != future && future.cancel(true)) {
            ITimerTaskHandler taskHandler = taskHandlerMap.get(taskKey);
            future = taskScheduler.schedule(() -> runTask(taskHandler), new CronTrigger(currentCron));

            taskCronMap.put(taskKey, currentCron);
            taskFutureMap.put(taskKey, future);

            TimerTaskHistory history = new TimerTaskHistory();
            history.setFuture(future);
            history.setCron(currentCron);
            futureMap.computeIfAbsent(taskKey, k -> new ArrayList<>()).add(history);

            log.info("TimerTaskManager restartTask success, taskKey: {}, cron: {}", taskKey, currentCron);
        }
    }

    /**
     * 停止任务
     */
    public void stopTask(String taskKey) {
        log.info("TimerTaskManager stopTask, taskKey: {}", taskKey);

        ScheduledFuture future = taskFutureMap.get(taskKey);
        if(null != future) {
            future.cancel(true);
            log.info("TimerTaskManager stopTask success, taskKey: {}", taskKey);
        }
    }

    /**
     * 执行任务
     */
    public void executeOnce(String taskKey) {
        log.info("TimerTaskManager execute task once, taskKey: {}", taskKey);

        ITimerTaskHandler taskHandler = taskHandlerMap.get(taskKey);
        if(null != taskHandler) {
            taskScheduler.schedule(() -> taskHandler.execute(), new Date());
        }
    }

    /**
     * 运行定时任务
     */
    private void runTask(ITimerTaskHandler taskHandler) {
        TimerTaskRunInfo runInfo = new TimerTaskRunInfo();
        runInfo.setLastRunTime(new Date());

        TimeInterval timer = DateUtil.timer();
        try {
            taskHandler.execute();
            runInfo.setHasException(false);
        }catch (Exception e) {
            runInfo.setHasException(true);
            runInfo.setException(e.getMessage());
        }

        runInfo.setRunMilliseconds(timer.interval());
        TimerTaskManager.taskRunInfoMap.put(taskHandler, runInfo);
    }

    /**
     * 定时任务列表
     */
    public List<TimerTaskDto> taskList(Class<?> classType) {
        List<TimerTaskDto> timerTaskDtoList = new ArrayList<>();
        taskHandlerList.forEach(taskHandler -> {
            if(taskHandler.type().equals(classType)) {
                String key = taskKeyMap.get(taskHandler);

                // 任务基本信息
                TimerTaskDto timerTaskDto = new TimerTaskDto();
                timerTaskDto.setName(taskHandler.name());
                timerTaskDto.setDesc(taskHandler.desc());

                // 任务周期信息
                if(StrUtil.isEmpty(key)) {
                    timerTaskDto.setIsRun(false);
                }else {
                    ScheduledFuture scheduledFuture = taskFutureMap.get(key);
                    timerTaskDto.setKey(key);
                    timerTaskDto.setIsRun(!scheduledFuture.isCancelled());
                    timerTaskDto.setNum(futureMap.get(key).stream().filter(history -> !history.getFuture().isCancelled()).count());
                    timerTaskDto.setCron(taskCronMap.get(key));
                    timerTaskDto.setCronDesc(CronExpParserUtil.translateToChinese(taskCronMap.get(key)));
                    timerTaskDto.setDelay(scheduledFuture.getDelay(TimeUnit.MILLISECONDS));
                }

                // 任务运行时信息
                timerTaskDto.setRunInfo(taskRunInfoMap.get(taskHandler));

                timerTaskDtoList.add(timerTaskDto);
            }
        });

        return timerTaskDtoList;
    }

}
